package com.jy.rhin.config.ws;

import java.time.LocalDateTime;
import java.util.Base64;
import java.util.List;

import javax.annotation.PostConstruct;
import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.apache.cxf.binding.soap.SoapHeader;
import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.headers.Header;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.io.CachedOutputStream;
import org.apache.cxf.message.MessageContentsList;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
import org.springframework.stereotype.Component;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import com.jy.rhin.support.util.CertificateUtils;

import cn.hutool.core.util.XmlUtil;
import cn.org.chiss.rhin._2015.document.repository.ProvideAndRegisterDocumentSet;
import lombok.extern.slf4j.Slf4j;

@Component
@Slf4j
/**
 * 客户端加载安全证书并签名
 * 
 * @author TJT
 *
 */
public class ClientAuthInterceptor extends AbstractPhaseInterceptor<SoapMessage> {

	public String wsse = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";
	public String wsu = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd";
	public String ds = "http://www.w3.org/2000/09/xmldsig#";
	public String ec = "http://www.w3.org/2001/10/xml-exc-c14n#";
	Document doc;
	public String priKey = "MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQg6wDS5IGLORZcpIidTU3wRrwniKyY3sLbLant/uY7o/KgCgYIKoZIzj0DAQehRANCAATXj1+oQfjSExLcss1AtZIlhGKgZiPxEDTOVYHBgbPXILpgou5wRJaUF+m8NmIpiB/HbyUVk/U+NpMdjzbZ6pur";

	public ClientAuthInterceptor() {
		super(Phase.PREPARE_SEND);
	}

	@PostConstruct
	public void init() throws ParserConfigurationException {
		DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
		doc = docBuilderFactory.newDocumentBuilder().newDocument();
	}

	@Override
	public void handleMessage(SoapMessage message) throws Fault {
		try {
			QName qname = new QName("http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd",
					"Security", "");
			String body = "";

			List out = message.getContent(List.class);
			if (out.get(0) instanceof ProvideAndRegisterDocumentSet) {
				body = new String(Base64.getEncoder().encode(((ProvideAndRegisterDocumentSet)out.get(0)).getDocument().get(0).getContent()));
			}
			SoapHeader s = new SoapHeader(qname, build(body));
			List<Header> headers = message.getHeaders();
			headers.add(s);
			message.put(Header.HEADER_LIST, headers);
		} catch (Exception e) {
			e.printStackTrace();
			log.error("证书加载失败");
		}

	}

	public Element build(String body) throws ParserConfigurationException, DOMException {

		Element element = doc.createElementNS(wsse, "wsse:Security");
		element.setAttribute("xmlns:wsse",
				"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
		element.setAttribute("xmlns:wsu",
				"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd");
		Element timestamp = getTimestamp();
		element.appendChild(timestamp);
		Element binarySecurityToken = getBinarySecurityToken();
		element.appendChild(binarySecurityToken);
		element.appendChild(digest(binarySecurityToken, timestamp, body));
		return element;
	}

	private Element digest(Element binarySecurityToken, Element timestamp, String body) {
		// 摘要
		String bodydigest = CertificateUtils.digest(body);
		String cerdigest = CertificateUtils.digest(binarySecurityToken.getTextContent());
		String timestampdigest = CertificateUtils.digest(timestamp.getTextContent());

		Element Signature = doc.createElementNS(ds, "ds:Signature");
		Signature.setAttribute("Id", "SIG-74063B34A4513D474215258757494516");
		Signature.setAttribute("xmlns:ds", "http://www.w3.org/2000/09/xmldsig#");

		Element SignatureValue = doc.createElementNS(ds, "ds:SignatureValue");
		StringBuffer cerbuf = new StringBuffer();
		cerbuf.append("-----BEGIN CERTIFICATE-----\n");
		cerbuf.append(binarySecurityToken.getTextContent().trim());
		cerbuf.append("\n-----END CERTIFICATE-----");
		SignatureValue.setTextContent(
				CertificateUtils.sign(cerbuf.toString(), timestampdigest + cerdigest + bodydigest, priKey));
		Signature.appendChild(SignatureValue);

		Element KeyInfo = doc.createElementNS(ds, "ds:KeyInfo");
		KeyInfo.setAttribute("Id", "KI-74063B34A4513D474215258757494363");
		Element SecurityTokenReference = doc.createElementNS(wsse, "wsse:SecurityTokenReference");
		SecurityTokenReference.setAttribute("wsu:Id", "STR-74063B34A4513D474215258757494384");
		Element Reference = doc.createElementNS(wsse, "wsse:Reference");
		Reference.setAttribute("URI", "#X509-74063B34A4513D474215258757494322");
		Reference.setAttribute("ValueType",
				"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3");
		SecurityTokenReference.appendChild(Reference);
		KeyInfo.appendChild(SecurityTokenReference);
		Signature.appendChild(KeyInfo);

		Element SignedInfo = doc.createElementNS(ds, "ds:SignedInfo");
		Element CanonicalizationMethod = doc.createElementNS(ds, "ds:CanonicalizationMethod");
		CanonicalizationMethod.setAttribute("Algorithm", "http://www.w3.org/2001/10/xml-exc-c14n#");
		Element InclusiveNamespaces = doc.createElementNS(ec, "ec:InclusiveNamespaces");
		InclusiveNamespaces.setAttribute("PrefixList", "SOAP-ENV");
		InclusiveNamespaces.setAttribute("xmlns:ec", "http://www.w3.org/2001/10/xml-exc-c14n#");
		CanonicalizationMethod.appendChild(InclusiveNamespaces);
		Element SignatureMethod = doc.createElementNS(ds, "ds:SignatureMethod");
		SignatureMethod.setAttribute("Algorithm", "SOAP-ENV");
		SignedInfo.appendChild(SignatureMethod);
		SignedInfo.appendChild(CanonicalizationMethod);
		Signature.appendChild(SignedInfo);
		Signature.appendChild(getReference("#TS-74063B34A4513D474215258757494131", timestampdigest));
		Signature.appendChild(getReference("#id-74063B34A4513D474215258757494465", bodydigest));
		Signature.appendChild(getReference("#X509-74063B34A4513D474215258757494322", cerdigest));
		return Signature;
	}

	private Element getReference(String url, String digest) {
		Element Reference = doc.createElementNS(ds, "ds:SignedInfo");
		Reference.setAttribute("URI", url);

		Element Transforms = doc.createElementNS(ds, "ds:Transforms");
		Element Transform = doc.createElementNS(ds, "ds:Transform");
		Transform.setAttribute("Algorithm", "http://www.w3.org/2001/10/xml-exc-c14n#");
		Transforms.appendChild(Transform);

		Element DigestMethod = doc.createElementNS(ds, "ds:DigestMethod");
		DigestMethod.setAttribute("Algorithm", "http://www.w3.org/2001/04/xmlenc#sha256");

		Element DigestValue = doc.createElementNS(ds, "ds:DigestValue");
		DigestValue.setTextContent(digest);

		Reference.appendChild(DigestValue);
		Reference.appendChild(Transforms);
		Reference.appendChild(DigestMethod);
		return Reference;
	}

	private Element getTimestamp() {
		Element Timestamp = doc.createElementNS(wsu, "wsu:Timestamp");
		Timestamp.setAttribute("wsu:Id", "TS-74063B34A4513D474215258757494131");
		Element Created = doc.createElementNS(wsu, "wsu:Created");
		Element Expires = doc.createElementNS(wsu, "wsu:Expires");
		String time = LocalDateTime.now().toString();
		Created.setTextContent(time);
		Expires.setTextContent(time);
		Timestamp.appendChild(Created);
		Timestamp.appendChild(Expires);
		return Timestamp;
	}

	private Element getBinarySecurityToken() {
		Element BinarySecurityToken = doc.createElementNS(wsse, "wsse:BinarySecurityToken");
		BinarySecurityToken.setAttribute("EncodingType",
				"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary");
		BinarySecurityToken.setAttribute("ValueType",
				"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3");
		BinarySecurityToken.setAttribute("wsu:Id", "X509-74063B34A4513D474215258757494322");
		BinarySecurityToken.setTextContent("MIIB/zCCAaSgAwIBAgIGAYhLmMsZMAoGCCqBHM9VAYN3MH0xCzAJBgNVBAYTAkNOMREwDwYDVQQIDAhaaGVKaWFuZzERMA8GA1UEBwwISGFuZ1pob3UxFDASBgNVBAoMC0p1WWlaaGlMaWFuMRQwEgYDVQQLDAtRdWFuTWluUGxhdDEcMBoGA1UEAwwTd3d3Lmp1eWl6aGlsaWFuLmNvbTAeFw0yMzA1MjExNjAwMDBaFw0yMzA1MjIxNjAwMDBaMH0xCzAJBgNVBAYTAkNOMREwDwYDVQQIDAhaaGVKaWFuZzERMA8GA1UEBwwISGFuZ1pob3UxFDASBgNVBAoMC0p1WWlaaGlMaWFuMRQwEgYDVQQLDAtRdWFuTWluUGxhdDEcMBoGA1UEAwwTd3d3Lmp1eWl6aGlsaWFuLmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABNePX6hB+NITEtyyzUC1kiWEYqBmI/EQNM5VgcGBs9cgumCi7nBElpQX6bw2YimIH8dvJRWT9T42kx2PNtnqm6ujEDAOMAwGA1UdEwQFMAMBAf8wCgYIKoEcz1UBg3cDSQAwRgIhAJt8e37QNURfGHxae0bxqX4kYZPsgyUw1tzv1OSEsRByAiEAtdAD7pnetRLNVngtMXhkoCdfeXhZNm/NE8S6siVlnC4=");
		return BinarySecurityToken;
	}

}
